package 多线程;

import java.lang.Thread.State;
import java.util.concurrent.locks.LockSupport;
/*
中断线程
如果线程需要执行一个长时间任务，就可能需要能中断线程。中断线程就是其他线程给该线程发一个信号，该线程收到信号后结束执行run()方法，
使得自身线程能立刻结束运行。

我们举个栗子：假设从网络下载一个100M的文件，如果网速很慢，用户等得不耐烦，就可能在下载过程中点“取消”，这时，程序就需要中断下载线
程的执行。

中断一个线程非常简单，只需要在其他线程中对目标线程调用interrupt()方法，目标线程需要反复检测自身状态是否是interrupted状态，如果是，就立刻结束运行。

我们还是看示例代码：
*/
/*
public class 中断线程 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new MyThread();
        t.start();
        Thread.sleep(8); // 暂停1毫秒，为了演示，让t线程运行1毫秒
        t.interrupt(); // 中断t线程 给t线程发出中断信号，t线程检测中断信号，中断run()方法
        t.join(); // main线程等待t线程结束
        System.out.println("end");
    }
}

class MyThread extends Thread {
    public void run() {
        int n = 0;
        while (! isInterrupted()) {
            n ++;
            System.out.println(n + " hello!");
        }
    }
}
*/
/*
仔细看上述代码，main线程通过调用t.interrupt()方法中断t线程，但是要注意，interrupt()方法仅仅向t线程发出了“中断请求”，
至于t线程是否能立刻响应，要看具体代码。而t线程的while循环会检测isInterrupted()，所以上述代码能正确响应interrupt()
请求，使得自身立刻结束运行run()方法。

如果线程处于等待状态，例如，main运行t.join()会让main线程进入等待状态，此时，如果对main线程调用interrupt()，join()方法会立
刻抛出InterruptedException，因此，目标线程只要捕获到join()方法抛出的InterruptedException，就说明有其他线程对
其调用了interrupt()方法，通常情况下该线程应该立刻结束运行。

我们来看下面的示例代码：

 中断线程
 */
/*
public class 中断线程 {
	public static void main(String[] args) throws InterruptedException {
		Thread t = new MyThread();
		t.start();
		Thread.sleep(1000);
		System.out.println("t线程状态："+t.getState());
		t.interrupt(); // 中断t线程   中断是由线程外部即调用程序发出，由线程内部响应
		System.out.println("Interrupt " + t.isInterrupted());
		t.join(); // 等待t线程结束
		System.out.println("Interrupt " + t.isInterrupted());
		System.out.println("end");
	}
}

class MyThread extends Thread {// t
	public void run() {
		Thread hello = new HelloThread();
		System.out.println(hello.getState());//NEW
		hello.start(); // 启动hello线程
		System.out.println(hello.getState());//RUNNABLE
		try {
			hello.join(); // 等待hello线程结束
		} catch (InterruptedException e) {//捕获由main发出的中断请求
			System.out.println("main是否发出Interrupt ----" + isInterrupted());
			System.out.println("hello线程状态："+hello.getState());//TIMED_WAITING
			System.out.println("catch t interrupted");
			System.out.println("interrupted!");
			hello.interrupt();// 向hello线程发出中断请求,必须通知hello线程中断，否则hello线程不会停止。
			System.out.println(hello.getState());
			System.out.println("Interrupt hello " + hello.isInterrupted());
		}
		System.out.println(hello.getState());
	}
}

class HelloThread extends Thread {// hello
	public void run() {
		int n = 0;
		while (!isInterrupted()) {
			n++;
			System.out.println(n + " hello!");
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				System.out.println("hello break!");
				break;
			}
		}
	}
}
*/
/*
main线程通过调用t.interrupt()从而通知t线程中断，而此时t线程正位于hello.join()的等待中，此方法会立刻结束等待并抛出InterruptedException。由于我
们在t线程中捕获了InterruptedException，因此，就可以准备结束该线程。在t线程结束前，对hello线程也进行了interrupt()调用通知其中断。如果去掉这一行代
码，可以发现hello线程仍然会继续运行，且JVM不会退出。

另一个常用的中断线程的方法是设置标志位。我们通常会用一个running标志位来标识线程是否应该继续运行，在外部线程中，通过
把HelloThread.running置为false，就可以让线程结束：
*/
// 中断线程
/*
public class 中断线程 {
    public static void main(String[] args)  throws InterruptedException {
        HelloThread t = new HelloThread();
        t.start();
        Thread.sleep(8);
        t.running = false; // main将running标志位置变成为false
    }
}

class HelloThread extends Thread {
    public volatile boolean running = true;//共享变量：立即将最新值由工作内存写入主内存，保证各个线程获得最新变量值
    public void run() {
        int n = 0;
        while (running) {
            n ++;
            System.out.println(n + " hello!");
        }
        System.out.println("end!");
    }
}
*/
/*
注意到HelloThread的标志位boolean running是一个线程间共享的变量。线程间共享变量需要使用volatile关键字标记，确保每个线程都能读取到更新后的变量值。

为什么要对线程间共享的变量用关键字volatile声明？这涉及到Java的内存模型。在Java虚拟机中，变量的值保存在主内存中，但是，当线程访问变量时，它会先获取一个副
本，并保存在自己的工作内存中。如果线程修改了变量的值，虚拟机会在某个时刻把修改后的值回写到主内存，但是，这个时间是不确定的！

┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
           Main Memory
│                               │
   ┌───────┐┌───────┐┌───────┐
│  │ var A ││ var B ││ var C │  │
   └───────┘└───────┘└───────┘
│     │ ▲               │ ▲     │
 ─ ─ ─│─│─ ─ ─ ─ ─ ─ ─ ─│─│─ ─ ─
      │ │               │ │
┌ ─ ─ ┼ ┼ ─ ─ ┐   ┌ ─ ─ ┼ ┼ ─ ─ ┐
      ▼ │               ▼ │
│  ┌───────┐  │   │  ┌───────┐  │
   │ var A │         │ var C │
│  └───────┘  │   │  └───────┘  │
   Thread 1          Thread 2
└ ─ ─ ─ ─ ─ ─ ┘   └ ─ ─ ─ ─ ─ ─ ┘
这会导致如果一个线程更新了某个变量，另一个线程读取的值可能还是更新前的。例如，主内存的变量a = true，线程1执行a = false时，它在此刻仅仅是把变量a的副本变
成了false，主内存的变量a还是true，在JVM把修改后的a回写到主内存之前，其他线程读取到的a的值仍然是true，这就造成了多线程之间共享的变量不一致。

因此，volatile关键字的目的是告诉虚拟机：
◾每次访问变量时，总是获取主内存的最新值；
◾每次修改变量后，立刻回写到主内存。

volatile关键字解决的是可见性问题：当一个线程修改了某个共享变量的值，其他线程能够立刻看到修改后的值。

如果我们去掉volatile关键字,运行上述程序,发现效果和带volatile差不多,这是因为在x86的架构下,JVM回写主内存的速度非常快,但是,换成ARM的架构,就会有显著的延迟。

小结
对目标线程调用interrupt()方法可以请求中断一个线程，目标线程通过检测isInterrupted()标志获取自身是否已中断。如果目标线程处于等待状态，该线程会捕获
到InterruptedException；

目标线程检测到isInterrupted()为true或者捕获了InterruptedException都应该立刻结束自身线程；

通过标志位判断需要正确使用volatile关键字；

volatile关键字解决了共享变量在线程间的可见性问题。
*/
/*《Java中对线程中断机制的实现》

在我们的程序中经常会有一些不达到目的不会退出的线程，例如：我们有一个下载程序线程，该线程在没有下载成功之前是不会退出的，若此
时用户觉得下载速度慢，不想下载了，这时就需要用到我们的线程中断机制了，告诉线程，你不要继续执行了，准备好退出吧。当然，线程在不同的状态
下遇到中断会产生不同的响应，有的会抛出异常，有的则没有变化，有的则会结束线程。本篇将从以下两个方面来介绍Java中对线程中断机制的具体实现：

◾Java中对线程中断所提供的API支持
◾线程在不同状态下对于中断所产生的反应

一、Java中对线程中断所提供的API支持
   在以前的jdk版本中，我们使用stop方法中断线程，但是现在的jdk版本中已经不再推荐使用该方法了，反而由以下三个方法完成对线程中断的支持。

1.public boolean isInterrupted()
2.public void interrupt()
3.public static boolean interrupted()
 
每个线程都一个状态位用于标识当前线程对象是否是中断状态。isInterrupted是一个实例方法，主要用于判断当前线程对象的中断标志位是否
被标记了，如果被标记了则返回true表示当前已经被中断，否则返回false。我们也可以看看它的实现源码：

1.public boolean isInterrupted()

public boolean isInterrupted() {
    return isInterrupted(false);
}

private native boolean isInterrupted(boolean ClearInterrupted);
底层调用的本地方法isInterrupted，传入一个boolean类型的参数，用于指定调用该方法之后是否需要清除该线程对象的中断标识位。
从这里我们也可以看出来，   调用isInterrupted并不会清除线程对象的中断标识位。

2.interrupt是一个实例方法，该方法用于设置当前线程对象的中断标识位。

3.interrupted是一个静态的方法，用于返回当前线程是否被中断。

public static boolean interrupted() {
    return currentThread().isInterrupted(true);
}
private native boolean isInterrupted(boolean ClearInterrupted);
该方法用于判断当前线程是否被中断，并且该方法调用结束的时候会清空中断标识位。下面我们看看线程所处不同状态下对于中断操作的反应。

二、线程在不同状态下对于中断所产生的反应
   线程一共6种状态，分别是NEW，RUNNABLE，BLOCKED，WAITING，TIMED_WAITING，TERMINATED（Thread类中有一个State枚
举类型列举了线程的所有状态）。下面我们就将把线程分别置于上述的不同种状态，然后看看我们的中断操作对它们的影响。

public class Thread implements Runnable {
	...
	public enum State {
		NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED;
	}
	public State getState() {
        // get current thread state
        return jdk.internal.misc.VM.toThreadState(threadStatus);
    }
	...
}*/

//1、NEW和TERMINATED
//   线程的new状态表示还未调用start方法，还未真正启动。线程的terminated状态表示线程已经运行终止。这两个状态下调用中断方法
//来中断线程的时候，Java认为毫无意义，所以并不会设置线程的中断标识位，什么事也不会发生。例如：
public class 中断线程 {
	public static void main(String[] args) throws InterruptedException {

		Thread thread = new MyThread();
		thread.start();
		System.out.println(thread.getState());
		System.out.println(thread.isInterrupted());
		
		//当此命令提前至interrupt前,main线程堵塞，等待thread线程执行完成，main线程下一条命令interrupt无法执行，即无法向线程thread发出中断请求。所以陷入死循环。
		//thread.join();
		System.out.println(thread.getState());
		thread.interrupt();
		Thread.sleep(1000);
		System.out.println(thread.getState());
		thread.join();//堵塞main线程，thread线程完成后，唤醒main线程
		System.out.println(Thread.currentThread().getName()+": "+Thread.currentThread().getState());
		System.out.println(thread.isInterrupted());
	}
}

class MyThread extends Thread {
	public void run() {
		while (!isInterrupted()) {		
			System.out.println("线程启动。。。"+isInterrupted());
		}
	}
}
//输出结果如下：

//terminated状态：
/*
public static void main(String[] args) throws InterruptedException {

     Thread thread = new MyThread();
     thread.start();

     thread.join();
     System.out.println(thread.getState());

     thread.interrupt();

    System.out.println(thread.isInterrupted());

}
*/
/*
输出结果如下：

从上述的两个例子来看，对于处于new和terminated状态的线程对于中断是屏蔽的，也就是说中断操作对这两种状态下的线程是无效的。???

应该说：thread.join()命令提前至main线程执行interrupt前,main线程堵塞，等待thread线程执行完成，main线程thread.join()命令的下一条命令interrupt无
法执行，即无法向线程thread发出中断请求。所以陷入死循环。

2、RUNNABLE
   如果线程处于运行状态，那么该线程的状态就是RUNNABLE，但是不一定所有处于RUNNABLE状态的线程都能获得CPU运行，在某个时间
段，只能由一个线程占用CPU，那么其余的线程虽然状态是RUNNABLE，但是都没有处于运行状态。而我们处于RUNNABLE状态的线程在遭遇
中断操作的时候只会设置该线程的中断标志位，并不会让线程实际中断，想要发现本线程已经被要求中断了则需要用程序去判断。例如：
*/
//先定义一个线程类
/*
class MyThread extends Thread {

	@Override
	public void run() {
		while (true) {
			//System.out.println(this);// do something
		}
	}
}

public class 中断线程 {
	public static void main(String[] args) throws InterruptedException {

		Thread thread = new MyThread();
		thread.start();

		System.out.println("State1 "+thread.getState());

		thread.interrupt();
		Thread.sleep(1000);// 等到thread线程被中断之后
		System.out.println("Interrupt "+thread.isInterrupted());
		//thread.join();
		System.out.println("State2 "+thread.getState());
	}
}
*/
/*
我们定义的线程始终循环做一些事情，主线程启动该线程并输出该线程的状态，然后调用中断方法中断该线程并再次输出该线程的状态。总的输出结果如下：

State1 RUNNABLE
Interrupt true
State2 RUNNABLE

可以看到在我们启动线程之后，线程状态变为RUNNABLE，中断之后输出中断标志，显然中断位已经被标记，但是当我们再次输出线程状态的时候
发现，线程仍然处于RUNNABLE状态。很显然，处于RUNNBALE状态下的线程即便遇到中断操作，也只会设置中断标志位并不会实际中断线程运行。那么问题是，既然不能直接中断线
程，我要中断标志有何用处？
这里其实Java将这种权力交给了我们的程序，Java给我们提供了一个中断标志位，我们的程序可以通过if判断中断标志位是否被设置来中断我们的程序而不是系统强制的中断。例如：

修改MyThread类的run方法*/
/*
public void run(){
    while(true){
        if (Thread.currentThread().isInterrupted()){
            System.out.println("exit MyThread");
            break;
        }
    }
}
class MyThread extends Thread {

	@Override
	public void run(){
		while(true){
			if (Thread.currentThread().isInterrupted()){
				System.out.println("exit MyThread");
				System.out.println(this.getName());//thread-0
				System.out.println(Thread.currentThread().getThreadGroup().getName());//main
				break;
			}
		}
	}
}
*/
//main函数启动线程
/*
public class 中断线程 {
	public static void main(String[] args) throws InterruptedException {

		Thread thread = new MyThread();
		thread.start();

		System.out.println("State1 "+thread.getState());

		thread.interrupt();
		Thread.sleep(1000);// 等到thread线程被中断之后
		System.out.println("Interrupt "+thread.isInterrupted());
		thread.join();
		System.out.println("State2 "+thread.getState());
	}
}
*/
/*
线程一旦发现自己的中断标志为被设置了，立马跳出死循环。这样的设计好处就在于给了我们程序更大的灵活性。

3、BLOCKED
   当线程处于BLOCKED状态说明该线程由于竞争某个对象的锁失败而被挂在了该对象的阻塞队列上了。那么此时发起中断操作不会对该
线程产生任何影响，依然只是设置中断标志位。例如：

自定义线程类
*/
/*
class MyThread extends Thread {

	public synchronized static void doSomething() {
		while (true) {
			// do something
		}
	}

	@Override
	public void run() {
		doSomething();
	}

}
//这里我们自定义了一个线程类，run方法中主要就做一件事情，调用一个有锁的静态方法，该方法内部是一个死循环（占用该锁让其他线程阻塞）。
public class 中断线程 {

	public static void main(String[] args) throws InterruptedException {

		Thread thread1 = new MyThread();
		thread1.start();

		Thread thread2 = new MyThread();
		thread2.start();

		Thread.sleep(1000);
		System.out.println(thread1.getState());// RUNNABLE
		System.out.println(thread2.getState());// BLOCKED

		thread2.interrupt();
		System.out.println(thread1.isInterrupted());// false
		System.out.println(thread1.getState());// RUNNABLE
		System.out.println(thread2.isInterrupted());// true
		System.out.println(thread2.getState());// BLOCKED
		thread1.interrupt();
		
	}
}*/
/*
在我们的主线程中，我们定义了两个线程并按照定义顺序启动他们，显然thread1启动后便占用MyThread类锁，此后thread2在获取锁的时候一定
失败，自然被阻塞在阻塞队列上，而我们对thread2进行中断，输出结果如下：

从输出结果看来，thread2处于BLOCKED状态，执行中断操作之后，该线程仍然处于BLOCKED状态，但是中断标志位却已被修改。这种状态下的线程
和处于RUNNABLE状态下的线程是类似的，给了我们程序更大的灵活性去判断和处理中断。

4、WAITING/TIMED_WAITING
     这两种状态本质上是同一种状态，只不过TIMED_WAITING在等待一段时间后会自动释放自己，而WAITING则是无限期等待，需要其他线程调
     用notify方法释放自己。但是他们都是线程在运行的过程中由于缺少某些条件而被挂起在某个对象的等待队列上。当这些线程遇到中断操作的
     时候，会抛出一个InterruptedException异常，并清空中断标志位。例如：

定义一个线程类
*/
/*
class MyThread extends Thread {

	@Override
	public void run() {
		synchronized (this) {
			try {
				//wait();
				Thread.sleep(1000);//亦可，
			} catch (InterruptedException e) {
				//当捕获InterruptedException异常时，该线程的中断标志位被清空(由true变为false)。
				System.out.println("i am waiting but facing interruptexception now");
				System.out.println("this:  "+this.getState());
				System.out.println("this:  "+this.isInterrupted());
			}
		}
	}
}

//我们定义了一个线程类，其中run方法让当前线程阻塞到条件队列上，并且针对InterruptedException 进行捕获，如果遇到InterruptedException 异常则输出一行信息。
//main函数启动该线程
public class 中断线程 {
	public static void main(String[] args) throws InterruptedException {

		Thread thread = new MyThread();
		System.out.println(thread.getState());//NEW
		thread.start();

		Thread.sleep(500);
		thread.interrupt();
		System.out.println(thread.isInterrupted());//true
		Thread.sleep(1000);
		System.out.println(thread.getState());//TERMINATED

		//线程run方法捕获了InterruptedException异常，接着就看到该线程的中断标志位被清空(由true变为false)。
		System.out.println(thread.isInterrupted());//false
	}
}*/
/*
在main线程中我们启动一个MyThread线程，然后对其进行中断操作。

从运行结果看，当前程thread启动之后就被挂起到该线程对象的条件队列上，然后我们调用interrupt方法对该线程进行中断，输出了我们
在catch中的输出语句，显然是捕获了InterruptedException异常，接着就看到该线程的中断标志位被清空。

综上所述，我们分别介绍了不同种线程的不同状态下对于中断请求的反应。NEW和TERMINATED对于中断操作几乎是屏蔽的，RUNNABLE和BLOCKED类似，
对于中断操作只是设置中断标志位并没有强制终止线程，对于线程的终止权利依然在程序手中。WAITING/TIMED_WAITING状态下的线程对于中断操作是
敏感的，他们会抛出异常并清空中断标志位。*/
